Skip to content

[WIP] Inference of setuptools' own version from git history #4948

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 8 commits into
base: main
Choose a base branch
from

Conversation

abravalheri
Copy link
Contributor

@abravalheri abravalheri commented Apr 16, 2025

Summary of changes

This is a follow-up (and alternative approach to) #4537, #4532 and try to address some of the shortcomings identified.

The approach implemented is to call directly git describe --abbrev --match 'v?[0-9]*' --dirty falling back to read the latest version from NEWS.rst and adding a "dirty" local time-based version.

Potential points of discussion:

  • What happens if a "downstream" packager simply download a tar ball from Github or performs a shallow clone without tag history?

    In this PR, the version would be determined as follows:

    1. The custom function will read the latest version from NEWS.rst
    2. The custom function will add a time-based development marker (similar to something that already happens prior to the PR: https://github.com/pypa/setuptools/blob/v78.1.0/setup.cfg#L1-L3)

    So downstream packagers may see a "non-pristine"/"dirty" version string if they don't have access to the commit/tag history, which may be undesirable, but not prohibitive.

  • Are we reimplemented and "half-backing" functionality already present in setuptools-scm?

    Well, yes. But we take advantage that version tags in setuptools are very predictable to simplify the code and that we already have implemented some functionality that allow us to shoehorn malformed version strings into compliant ones.

    This means that we can implement the functionality with 3 lines 9 lines1 of code assuming the installed version of git supports the command git describe --abbrev --match 'v?[0-9]*' --dirty (which unless I am wrong is available at least since version 2.0.5 of git: https://git-scm.com/docs/git-describe/2.0.5).

    On top of that, this PR implements a functionality not present on setuptools-scm (AFAIK), extract a fallback version from NEWS.rst. All things considered the custom function implementation is less than 10 lines 15 lines1 of code. (It can be improved to handle more edge cases, but then it improves complexity)

Closes #4530

Pull Request Checklist

Footnotes

  1. Changed in aee4dc9 to consider fallback to PKG-INFO 2

@@ -71,6 +71,8 @@ jobs:
timeout-minutes: 75
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the absence of the commit/tag history it is not possible to infer the version correctly. So we need a deep checkout.

This has been discussed in https://github.com/pypa/setuptools/pull/4537/files#r1701658826.

The approach seems to be the standard workaround for the same problem in setuptools-scm, see pypa/setuptools-scm#480, pypa/setuptools-scm#952 (comment). Tracked in actions/checkout#249 and actions/checkout#1471.

except subprocess.CalledProcessError: # e.g.: git not installed or history missing
with open("NEWS.rst", encoding="utf-8") as fp:
match = re.search(r"v\d+\.\d+.\d+", fp.read()) # latest version
return f"{match[0] if match else '0.0.0'}.dev+{time.strftime('%Y%m%d')}"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

%Y%m%d can be changed to more specific time to improve monotonicity... Please let me know if a more specific tag would be better.

Copy link
Contributor Author

@abravalheri abravalheri Apr 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BTW, the except is the code path that takes effect when git tag version is not available (tarballs or shallow clones).

I have considered checking if a PKG-INFO file is available but that would increase the complexity of this function... Please let me know if this more complex approach should be followed...

Copy link
Contributor Author

@abravalheri abravalheri Apr 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, it may be necessary to check for PKG-INFO, because otherwise we may see inconsistency between sdist and wheel the following behaviour when running python -m build:

$ python -m build
Successfully built setuptools-78.1.2.tar.gz and setuptools-78.1.2.dev0+20250416-py3-none-any.whl

Copy link
Contributor Author

@abravalheri abravalheri Apr 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, it may be necessary to check for PKG-INFO, because otherwise we may see the following behaviour when running python -m build:

So I inevitably had to add some lines in aee4dc9 to deal with this problem:

https://github.com/pypa/setuptools/pull/4948/files#diff-60f61ab7a8d1910d86d9fda2261620314edcae5894d5aaa236b821c7256badd7R39-R42

It does increase the complexity of the solution.

We can see now consistency between version inference in sdist and wheel: https://github.com/pypa/setuptools/actions/runs/14501313828/job/40681414420?pr=4948#step:8:3078

@@ -12,7 +12,7 @@
_VALID_NAME = re.compile(r"^([A-Z0-9]|[A-Z0-9][A-Z0-9._-]*[A-Z0-9])$", re.I)
_UNSAFE_NAME_CHARS = re.compile(r"[^A-Z0-9._-]+", re.I)
_NON_ALPHANUMERIC = re.compile(r"[^A-Z0-9]+", re.I)
_PEP440_FALLBACK = re.compile(r"^v?(?P<safe>(?:[0-9]+!)?[0-9]+(?:\.[0-9]+)*)", re.I)
_PEP440_FALLBACK = re.compile(r"^(?P<safe>v?(?:[0-9]+!)?[0-9]+(?:\.[0-9]+)*)", re.I)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an existing bug that I have identified when working on this PR.
I added a new doctest to avoid regression down in the same file:

    >>> best_effort_version("v78.1.0-2-g3a3144f0d")
    '78.1.0.dev0+sanitized.2.g3a3144f0d'

def best_effort_version(version: str) -> str:
def best_effort_version(
version: str,
template: str = "{safe}.dev0+sanitized.{sanitized}",
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This customisable template parameter is not strictly necessary, it can be removed if we don't mind versions looking like 78.1.0.dev0+sanitized.2.g3a3144f0d

@@ -102,8 +101,6 @@ setenv =
TWINE_USERNAME = {env:TWINE_USERNAME:__token__}
commands =
python -c "import shutil; shutil.rmtree('dist', ignore_errors=True)"
# unset tag_build and tag_date pypa/setuptools#2500
python setup.py egg_info -Db "" saveopts
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we would no longer need this.

@abravalheri abravalheri changed the title Auto version Inference of setuptools' own version from git history Apr 16, 2025
@abravalheri
Copy link
Contributor Author

Possibly needs more tests, but posting to collect feedback if the direction is viable.

@abravalheri
Copy link
Contributor Author

abravalheri commented Apr 16, 2025

Error with pytest-mypy in 3.14 seems unrelated:

image

@abravalheri abravalheri changed the title Inference of setuptools' own version from git history [WIP] Inference of setuptools' own version from git history Apr 16, 2025
@abravalheri
Copy link
Contributor Author

@jaraco would this kind of approach be something acceptable, taking into consideration the previous discussions in #4530, #4537, #4532.

It is a bit of reimplementing functionality.

@abravalheri abravalheri requested a review from jaraco April 16, 2025 20:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Remove use of tag_build and tag_date in Setuptools
2 participants